package com.hucsmn.chatroom;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.regex.Pattern;

/**
 * 每个客户端首次连接聊天室时，需要发送的头信息。
 */
public class ChatHeaders {
    private static final Pattern REGEX_NUL = Pattern.compile("\0");

    /**
     * 最大头长度。
     */
    private static final int HEADER_LIMIT = 256;

    /**
     * 从流的开头处读取头信息。
     *
     * @param in 输入流。
     * @return 头字段数组。
     * @throws IOException 流解析错误或读取错误。
     */
    public static String[] readHeader(InputStream in) throws IOException {
        byte[] buf = new byte[HEADER_LIMIT];
        int size = 0;
        int b;
        boolean nul = false;
        while (size < buf.length && (b = in.read()) >= 0) {
            buf[size++] = (byte) b;
            if (nul && b == 0) {
                break;
            }
            nul = b == 0;
        }
        if (size < 2 || buf[size - 1] != 0 || buf[size - 2] != 0) {
            throw new MalformedChatHeaderException("empty stream or header too large");
        }

        InputStreamReader decoder = new InputStreamReader(
                new ByteArrayInputStream(buf, 0, size),
                StandardCharsets.UTF_8);
        char[] header = new char[HEADER_LIMIT];
        int length = 0;
        int c;
        while ((c = decoder.read()) >= 0) {
            header[length++] = (char) c;
        }

        return REGEX_NUL.split(String.valueOf(header, 0, length), 0);
    }

    /**
     * 写入头字段值。
     *
     * @param out 输出流。
     * @param header 头字段。
     * @throws IOException 字段含非法字符、头过长或者写入错误。
     */
    public static void writeHeader(OutputStream out, String... header) throws IOException {
        if (header.length == 0) {
            throw new MalformedChatHeaderException("header cannot be empty");
        }

        char[] buf = new char[HEADER_LIMIT];
        int size = 0;
        for (String field : header) {
            if (size + field.length() + 1 >= buf.length) {
                throw new MalformedChatHeaderException("header too large");
            }
            for (int i = 0; i < field.length(); i++) {
                char c = field.charAt(i);
                if (c == 0) {
                    throw new MalformedChatHeaderException("cannot encode nul");
                }
                buf[size++] = c;
            }
            buf[size++] = 0;
        }
        buf[size++] = 0;

        byte[] encoded = String.valueOf(buf, 0, size).getBytes(StandardCharsets.UTF_8);
        if (encoded.length > HEADER_LIMIT) {
            throw new MalformedChatHeaderException("header too large");
        }
        out.write(encoded);
        out.flush();
    }

    /**
     * 显示头信息的参数部分。
     *
     * @param header 头信息。
     * @return 头信息参数部分的字符串形式。
     */
    public static String headerArgumentsToString(String[] header) {
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i < header.length; i++) {
            sb.append(header[i]);
            if (i + 1 != header.length) {
                sb.append(" ");
            }
        }
        return sb.toString();
    }
}
